﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace tjb.Utility.IniReadWrite
{
    /// <summary>
    /// 字符与对象解析器
    /// <para>by tangjingbo at 2009-3-12 13:29</para>
    /// </summary>
    /// <summary>
    /// 字符与对象解析器
    /// <para>by tangjingbo at 2009-3-12 13:29</para>
    /// </summary>
    public class ParseUtil
    {
        /// <summary>
        /// 字段、列的分隔符号
        /// </summary>
        private static string FieldSeparator = (char)0 + "";
        /// <summary>
        /// 行的分隔符号
        /// </summary>
        private static string RowSeparator = (char)1 + "";

        /// <summary>
        /// 将一个二维表序列转化为list对象。
        /// <para>by tangjingbo at 2009-3-12 13:30</para>
        /// </summary>
        /// <param name="InString">The in string.</param>
        /// <returns></returns>
        public static List<List<string>> Parse(string InString)
        {
            List<List<string>> set = new List<List<string>>();

            string[] rows = InString.Split(new string[] { RowSeparator }, StringSplitOptions.RemoveEmptyEntries);
            int i = 0, n = rows.Length;
            for (; i < n; i++)
            {
                List<string> fs = new List<string>(rows[i].Split(new string[] { FieldSeparator }, StringSplitOptions.RemoveEmptyEntries));
                set.Add(fs);
            }

            return set;
        }
        private const string keyGName = "key";
        private const string valueGName = "value";
        /// <summary>
        /// ini文件键值分隔符
        /// </summary>
        private static string iniFieldSeparator = (char)3 + "";
        /// <summary>
        /// ini文件的行分隔符号
        /// </summary>
        private static string iniRowSeparator = (char)4 + "";
        private static Regex regtype = new Regex(@"^\[(?<type>.+)\][ \t]*$", RegexOptions.Multiline | RegexOptions.Compiled);
        private static Regex regIgnore = new Regex(@"^([ \t]*|[ \t]*;.*)$", RegexOptions.Multiline | RegexOptions.Compiled);
        private static Regex regItem = new Regex(@"^(?<" + keyGName + ">[^[(?:" + iniFieldSeparator + @")]+)(?:" + iniFieldSeparator + ")?(?<=" + iniFieldSeparator + ")?(?<" + valueGName + ">.*)$", RegexOptions.Multiline | RegexOptions.Compiled);
        /// <summary>
        /// 更改解析ini字符串的分隔
        /// <para>by tangjingbo at 2009-3-13 12:20</para>
        /// </summary>
        /// <param name="FieldSeparator">The field separator.</param>
        /// <param name="RowSeparator">The row separator.</param>
        public static void IniSeparatorChange(string FieldSeparator, string RowSeparator)
        {
            iniFieldSeparator = FieldSeparator;
            regItem = new Regex(@"^(?<" + keyGName + ">[^[(?:" + iniFieldSeparator + @")]+)(?:" + iniFieldSeparator + ")?(?<=" + iniFieldSeparator + ")?(?<" + valueGName + ">.*)$", RegexOptions.Multiline | RegexOptions.Compiled);
            iniRowSeparator = RowSeparator;
        }

        /// <summary>
        /// 将AcitonAttach实例转换成字符串
        /// <para>by tangjingbo at 2009-3-12 13:29</para>
        /// </summary>
        /// <param name="attach">The attach.</param>
        /// <returns></returns>
        public static StringBuilder AttachToStringBuilder(AcitonAttach attach)
        {
            if (attach == null) return new StringBuilder();

            StringBuilder sb = new StringBuilder();
            sb.Append("[" + attach.Section + "]" + iniRowSeparator);
            int i = 0, n = attach.Attaches.Count;

            if (attach.Section == "Rout")
            {
                for (; i < n; i++)
                {
                    AttachItem ai = attach.Attaches[i];
                    sb.Append(ai.Key + iniFieldSeparator + ai.Flag + iniRowSeparator);
                }
            }
            else
            {
                for (; i < n; i++)
                {
                    AttachItem ai = attach.Attaches[i];
                    sb.Append(ai.Key + iniFieldSeparator + ai.Value + iniRowSeparator);
                }
            }

            if (n > 0) sb.Length = sb.Length - iniRowSeparator.Length;
            return sb;
        }
        /// <summary>
        /// 
        /// <para>by tangjingbo at 2009-3-17 11:47</para>
        /// </summary>
        /// <param name="attach">The attach.</param>
        /// <returns></returns>
        public static String AttachToString(AcitonAttach attach)
        {
            return AttachToStringBuilder(attach).ToString();
        }
        /// <summary>
        /// 将字符串解析为AcitonAttach 实例
        /// <para>by tangjingbo at 2009-3-12 13:29</para>
        /// </summary>
        /// <param name="AttachStr">The attach STR.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentException">参数错误</exception>
        /// <exception cref="Exception"></exception>
        public static AcitonAttach StringToActionAttach(string AttachStr)
        {
            if (string.IsNullOrEmpty(AttachStr))
                return null;
            List<string> rows = new List<string>(AttachStr.Split(new string[] { iniRowSeparator }, StringSplitOptions.RemoveEmptyEntries));
            string type = "Undefined";

            int i = 0, n = rows.Count;


            for (; i < n; i++)
            {
                string cur = rows[i];
                if (regIgnore.IsMatch(cur))
                {
                    continue;
                }
                if (regtype.IsMatch(cur))
                {
                    Match m = regtype.Match(cur);

                    type = m.Groups["type"].Value;
                    break;
                }

            }


            AcitonAttach at = new AcitonAttach();
            at.Attaches = new List<AttachItem>();
            at.Section = type;
            if (type == "Data")
            {
                foreach (string cur in rows)
                {
                    if (regIgnore.IsMatch(cur))
                        continue;
                    if (regItem.IsMatch(cur))
                    {
                        Match m = regItem.Match(cur);
                        at.Attaches.Add(new AttachItem(m.Groups[keyGName].Value, m.Groups[valueGName].Value, m.Groups[valueGName].Value == "1"));
                    }
                }
            }
            else if (type == "Rout")
            {
                foreach (string cur in rows)
                {
                    if (regIgnore.IsMatch(cur))
                        continue;
                    if (regItem.IsMatch(cur))
                    {
                        Match m = regItem.Match(cur);
                        at.Attaches.Add(new AttachItem(m.Groups[keyGName].Value, m.Groups[valueGName].Value, false));
                    }
                }
            }
            else throw new Exception("未实现的 OperateType 类型");
            return at;
        }


        public static StringBuilder GetStringBuilder(List<AcitonAttach> attaches)
        {
            StringBuilder sb = new StringBuilder();

            int i = 0, n = attaches.Count;
            for (; i < n; i++)
            {
                sb.Append(AttachToStringBuilder(attaches[i]) + iniRowSeparator);
            }
            if (n > 0) sb.Length = sb.Length - iniRowSeparator.Length;
            return sb;
        }
        /// <summary>
        /// 
        /// <para>by tangjingbo at 2009-3-17 10:28</para>
        /// </summary>
        /// <param name="AttachStr">The attach STR.</param>
        /// <returns></returns>
        public static List<AcitonAttach> GetAttachList(string AttachStr)
        {
            List<AcitonAttach> attaches = new List<AcitonAttach>();

            if (string.IsNullOrEmpty(AttachStr))
                return null;
            List<string> rows = new List<string>(AttachStr.Split(new string[] { iniRowSeparator }, StringSplitOptions.RemoveEmptyEntries));
            string type = "Undefined";

            int i = 0, n = rows.Count;

            AcitonAttach att = null;

            for (; i < n; i++)
            {
                string cur = rows[i];
                if (regIgnore.IsMatch(cur))
                {
                    continue;
                }
                if (regtype.IsMatch(cur))
                {
                    Match m = regtype.Match(cur);
                    type = m.Groups["type"].Value;
                    if (att == null)
                    {
                        att = new AcitonAttach();
                        att.Section = type;
                        att.Attaches = new List<AttachItem>();
                    }
                    else if (type != att.Section)
                    {
                        attaches.Add(att);
                        att = new AcitonAttach();
                        att.Section = type;
                        att.Attaches = new List<AttachItem>();
                    }
                    else
                    {

                    }
                    continue;
                }
                if (regItem.IsMatch(cur))
                {
                    Match m = regItem.Match(cur);
                    att.Attaches.Add(new AttachItem(m.Groups[keyGName].Value, m.Groups[valueGName].Value, m.Groups[valueGName].Value == "1"));
                }
                if (i == n - 1)
                    attaches.Add(att);
            }

            return attaches;
        }

    }
}
